#include <boost/tti/has_type.hpp>
#include <boost/tti/has_member_function.hpp>
#include <type_traits>

namespace vex { namespace iterable { namespace stl_interop {
    BOOST_TTI_HAS_TYPE(iterator);
    BOOST_TTI_HAS_TYPE(const_iterator);
    BOOST_TTI_HAS_TYPE(iterator_category);
    BOOST_TTI_HAS_MEMBER_FUNCTION(begin);
    BOOST_TTI_HAS_MEMBER_FUNCTION(end);

    /// invokable if has_type_const_iterator<T>::value is false
    template<class, bool HasIterator = false>
    struct has_const_member_functions_begin_and_end : public std::false_type {};

    /// invokable if has_type_const_iterator<T>::value is true
    template<class T>
    struct has_const_member_functions_begin_and_end<T, true> : public std::conditional<
        has_member_function_begin<const T, typename T::const_iterator>::value &&
        has_member_function_end<const T, typename T::const_iterator>::value,
        std::true_type,
        std::false_type
    >::type {};

    /// invokable if has_type_iterator<T>::value is false
    template<class, bool HasIterator = false>
    struct has_member_functions_begin_and_end : public std::false_type {};

    /// invokable if has_type_iterator<T>::value is true
    template<class T>
    struct has_member_functions_begin_and_end<T, true> : public std::conditional<
        has_member_function_begin<T, typename T::iterator>::value &&
        has_member_function_end<T, typename T::iterator>::value,
        std::true_type,
        std::false_type
    >::type {};

    /// determines whether <paramref name="T"/> can be used as stl range
    template<class T> struct is_container {
        typedef typename std::decay<T>::type decayed_type;
        static const bool value = has_const_member_functions_begin_and_end<
            decayed_type, 
            has_type_const_iterator<decayed_type>::value
        >::value;
    };
}}}